import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler


def load_and_check_data(filename='新浪财经历史分红数据.xlsx'):
    """
    读取Excel文件并进行基本检查
    :param filename: 文件名
    :return: 读取的数据框
    """
    try:
        df = pd.read_excel(filename, engine='openpyxl')
        print(f"成功读取文件，数据形状为: {df.shape}")
        
        # 检查重复值
        print("\n=== 重复值检查 ===")
        
        # 检查变量"股票代码"的重复值
        code_duplicates = df['股票代码'].duplicated().sum() if '股票代码' in df.columns else 0
        if '股票代码' in df.columns:
            print(f"变量'股票代码'中存在{code_duplicates}个重复值")
        elif '代码' in df.columns:
            code_duplicates = df['代码'].duplicated().sum()
            print(f"变量'代码'中存在{code_duplicates}个重复值")
        else:
            print("未找到代码相关列")
        
        # 检查变量"股票名称"的重复值
        name_duplicates = df['股票名称'].duplicated().sum() if '股票名称' in df.columns else 0
        if '股票名称' in df.columns:
            print(f"变量'股票名称'中存在{name_duplicates}个重复值")
        elif '名称' in df.columns:
            name_duplicates = df['名称'].duplicated().sum()
            print(f"变量'名称'中存在{name_duplicates}个重复值")
        else:
            print("未找到名称相关列")
        
        # 检查变量"详细"的重复值
        if '详细' in df.columns:
            detail_duplicates = df['详细'].duplicated().sum()
            print(f"变量'详细'中存在{detail_duplicates}个重复值")
        else:
            print("变量'详细'不存在于数据中")
            # 检查是否有其他类似的列名
            similar_columns = [col for col in df.columns if '详' in col or 'detail' in col.lower()]
            if similar_columns:
                print(f"找到类似的列: {similar_columns}")
                # 对找到的类似列也进行重复值检查
                for col in similar_columns:
                    col_duplicates = df[col].duplicated().sum()
                    print(f"变量'{col}'中存在{col_duplicates}个重复值")
        
        return df
        
    except Exception as e:
        print(f"读取文件时发生错误: {str(e)}")
        return None


def show_data_preview(df):
    """
    展示数据前5行，观察数据存在的问题
    :param df: 数据框
    """
    if df is None or df.empty:
        print("没有数据可展示。")
        return
    
    print("\n=== 数据前5行预览 ===")
    print(df.head())
    
    # 检查数据类型
    print("\n=== 数据类型信息 ===")
    print(df.dtypes)
    
    # 检查缺失值
    print("\n=== 缺失值检查 ===")
    print(df.isnull().sum())


def process_listing_date(df):
    """
    对"上市日期"进行处理，提取年、月、日变量
    :param df: 数据框
    :return: 处理后的数据框
    """
    if df is None or df.empty:
        return df
    
    # 查找日期相关的列
    date_columns = [col for col in df.columns if '上市' in col and ('日期' in col or '时间' in col)]
    
    if not date_columns:
        print("未找到包含'上市日期'或类似名称的列。")
        # 尝试查找其他可能的日期列，比如发布日期
        possible_date_cols = [col for col in df.columns if '日期' in col or 'date' in col.lower()]
        if possible_date_cols:
            print(f"找到以下可能的日期列: {possible_date_cols}")
            # 对第一个找到的日期列进行处理
            date_col = possible_date_cols[0]
            print(f"尝试处理日期列: {date_col}")
            
            try:
                # 尝试将列转换为日期类型
                # 先查看一下数据格式
                print(f"{date_col}列的前几个值: {df[date_col].head().tolist()}")
                
                # 处理不同格式的日期
                if df[date_col].dtype == 'object':
                    # 如果是字符串类型，尝试转换
                    try:
                        # 检查是否是MM-DD格式（不含年份）
                        sample_date = df[date_col].dropna().iloc[0] if not df[date_col].dropna().empty else ''
                        if '-' in sample_date and len(sample_date.split('-')) == 2:
                            # 添加默认年份（使用当前年份）
                            from datetime import datetime
                            current_year = datetime.now().year
                            # 处理MM-DD格式，添加年份
                            df[date_col] = pd.to_datetime(
                                df[date_col].apply(lambda x: f"{current_year}-{x}" if pd.notna(x) and x else x),
                                errors='coerce'
                            )
                        else:
                            # 尝试其他格式
                            df[date_col] = pd.to_datetime(df[date_col], errors='coerce')
                    except Exception as e:
                        print(f"无法将{date_col}转换为日期类型: {str(e)}")
                
                # 提取年、月、日
                if pd.api.types.is_datetime64_any_dtype(df[date_col]):
                    df[f'{date_col}_年'] = df[date_col].dt.year
                    df[f'{date_col}_月'] = df[date_col].dt.month
                    df[f'{date_col}_日'] = df[date_col].dt.day
                    print(f"成功从{date_col}提取年、月、日信息。")
                else:
                    print(f"无法从{date_col}提取日期信息，数据类型不是日期")
            except Exception as e:
                print(f"处理日期时发生错误: {str(e)}")
        return df
    
    date_col = date_columns[0]  # 选择第一个找到的列
    print(f"正在处理日期列: {date_col}")
    
    try:
        # 尝试将列转换为日期类型
        df[date_col] = pd.to_datetime(df[date_col], errors='coerce')
        
        # 提取年、月、日
        df[f'{date_col}_年'] = df[date_col].dt.year
        df[f'{date_col}_月'] = df[date_col].dt.month
        df[f'{date_col}_日'] = df[date_col].dt.day
        
        print(f"成功从{date_col}提取年、月、日信息。")
        
    except Exception as e:
        print(f"处理日期时发生错误: {str(e)}")
    
    return df


def normalize_numeric_variables(df):
    """
    对特定数值型变量进行数据归一化处理："累计股息(%)" "年均股息(%)" "分红次数" "融资总额(亿元)"
    :param df: 数据框
    :return: 处理后的数据框
    """
    if df is None or df.empty:
        return df
    
    # 定义需要归一化的特定变量
    required_vars = ["累计股息(%)", "年均股息(%)", "分红次数", "融资总额(亿元)"]
    
    # 创建归一化器
    scaler = MinMaxScaler()
    
    # 找出实际存在的数据列
    available_vars = []
    for var in required_vars:
        # 尝试直接匹配或模糊匹配列名
        matched_cols = [col for col in df.columns if var in col or var.replace('(', '').replace(')', '') in col]
        if matched_cols:
            available_vars.append(matched_cols[0])
    
    if not available_vars:
        print(f"未找到指定的变量: {required_vars}")
        # 作为备用方案，尝试找出所有数值型变量
        numeric_cols = []
        for col in df.columns:
            try:
                if df[col].dtype == 'object':
                    cleaned_col = df[col].str.replace('%', '').str.replace('--', '0').str.strip()
                    pd.to_numeric(cleaned_col, errors='raise')
                    numeric_cols.append(col)
                elif np.issubdtype(df[col].dtype, np.number):
                    numeric_cols.append(col)
            except:
                continue
        
        if numeric_cols:
            print(f"将对以下找到的数值型变量进行归一化处理: {numeric_cols}")
            available_vars = numeric_cols
        else:
            print("没有找到可归一化的数值型变量。")
            return df
    else:
        print(f"将对以下找到的变量进行归一化处理: {available_vars}")
    
    try:
        # 创建一个副本，避免修改原数据
        df_copy = df.copy()
        
        # 处理每个数值列
        for col in available_vars:
            if df_copy[col].dtype == 'object':
                # 清理字符串类型的数值
                df_copy[col] = df_copy[col].str.replace('%', '').str.replace('--', '0').str.strip()
                df_copy[col] = pd.to_numeric(df_copy[col], errors='coerce')
        
        # 填充缺失值
        df_copy[available_vars] = df_copy[available_vars].fillna(df_copy[available_vars].mean())
        
        # 进行归一化
        normalized_data = scaler.fit_transform(df_copy[available_vars])
        
        # 创建新的归一化列
        normalized_df = pd.DataFrame(
            normalized_data,
            columns=[f'{col}_归一化' for col in available_vars],
            index=df.index
        )
        
        # 合并到原数据框
        df = pd.concat([df, normalized_df], axis=1)
        
        print("数据归一化处理完成。")
        
    except Exception as e:
        print(f"归一化处理时发生错误: {str(e)}")
    
    return df


def save_preprocessed_data(df, filename='新浪财经历史分红数据_预处理.xlsx'):
    """
    保存预处理后的数据
    :param df: 处理后的数据框
    :param filename: 文件名
    """
    if df is None or df.empty:
        print("没有数据可保存。")
        return
    
    try:
        df.to_excel(filename, index=False, engine='openpyxl')
        print(f"预处理后的数据已成功保存到{filename}。")
    except Exception as e:
        print(f"保存预处理后的数据时发生错误: {str(e)}")


def main():
    """
    主函数
    """
    print("开始数据预处理任务...")
    
    # 加载并检查数据
    df = load_and_check_data()
    if df is None or df.empty:
        print("数据加载失败，无法继续预处理。")
        return
    
    # 展示数据前5行
    show_data_preview(df)
    
    # 处理上市日期
    df = process_listing_date(df)
    
    # 归一化数值型变量
    df = normalize_numeric_variables(df)
    
    # 保存预处理后的数据
    save_preprocessed_data(df)
    
    print("数据预处理任务完成。")


if __name__ == "__main__":
    main()